-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better stack list experience with Kubernetes and Swarm #1031
Conversation
⛑ comes after #991, only the 5 last commits are new. |
cli/command/stack/cmd.go
Outdated
@@ -27,9 +27,6 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command { | |||
newServicesCommand(dockerCli), | |||
) | |||
flags := cmd.PersistentFlags() | |||
flags.String("namespace", "default", "Kubernetes namespace to use") | |||
flags.SetAnnotation("namespace", "kubernetes", nil) | |||
flags.SetAnnotation("namespace", "experimentalCLI", nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should stay
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was moved into each sub-command, so still there in a way.
cli/command/stack/deploy.go
Outdated
@@ -45,5 +51,6 @@ func newDeployCommand(dockerCli command.Cli) *cobra.Command { | |||
`Query the registry to resolve image digest and supported platforms ("`+swarm.ResolveImageAlways+`"|"`+swarm.ResolveImageChanged+`"|"`+swarm.ResolveImageNever+`")`) | |||
flags.SetAnnotation("resolve-image", "version", []string{"1.30"}) | |||
flags.SetAnnotation("resolve-image", "swarm", nil) | |||
kubernetes.InstallFlags(flags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why making these flags per stack subcommand instead of putting the on the stack
command and make the subcommand inherit ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because stack ls now needs a different behaviour than other stack sub-commands for --namespace and we cannot set it once with type string and another time with []string (e.g. several namespaces).
So the drawback is a bit of code duplication setting the flags for all sub-commands, which was factorized into kubernetes.InstallFlags
cli/command/stack/list.go
Outdated
}, | ||
} | ||
|
||
flags := cmd.Flags() | ||
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template") | ||
flags.StringSliceVar(&opts.Namespaces, "namespace", []string{"default"}, "Kubernetes namespaces to use") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will setting a default here will override the default namespace defined in the context ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yes, I suppose it will, which is likely a bug.
However I don't think this has been introduced by this PR as the default for --namespace
was already default
.
Could this be fixed in a follow up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually there is code in kubernetes.WrapCli
to deal with that and it seems to be working as expected
> docker stack ls --orchestrator=kubernetes
stacks.compose.docker.com is forbidden: User "uu" cannot list stacks.compose.docker.com in the namespace "default": access denied
> kubectl config set-context ucp_34.209.72.126:6443_uu --namespace=tutu
Context "ucp_34.209.72.126:6443_uu" modified.
> docker stack ls --orchestrator=kubernetes
NAME SERVICES ORCHESTRATOR NAMESPACE
dtc 5 Kubernetes tutu
cli/command/stack/list.go
Outdated
flags.SetAnnotation("namespace", "kubernetes", nil) | ||
flags.SetAnnotation("namespace", "experimentalCLI", nil) | ||
flags.BoolVarP(&opts.AllNamespaces, "all-namespaces", "", false, "List stacks among all Kubernetes namespaces") | ||
flags.SetAnnotation("all-namespaces", "kubernetes", nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all-namespaces
should probably be marked as experimentalCLI
too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'll add that, thanks.
cli/command/stack/list.go
Outdated
Output: dockerCli.Out(), | ||
Format: formatter.NewStackFormat(format), | ||
} | ||
sort.Slice(stacks, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sort.Slice(stacks, func(i, j int) bool { …
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
cli/command/stack/list_test.go
Outdated
)}, nil | ||
}, | ||
}) | ||
cli.SetClientInfo(func() command.ClientInfo { return command.ClientInfo{Orchestrator: "swarm"} }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
cli/command/stack/list_test.go
Outdated
@@ -86,6 +91,7 @@ func TestListWithoutFormat(t *testing.T) { | |||
)}, nil | |||
}, | |||
}) | |||
cli.SetClientInfo(func() command.ClientInfo { return command.ClientInfo{Orchestrator: "swarm"} }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here …
cli/command/stack/list_test.go
Outdated
@@ -139,6 +145,7 @@ func TestListOrder(t *testing.T) { | |||
return uc.swarmServices, nil | |||
}, | |||
}) | |||
cli.SetClientInfo(func() command.ClientInfo { return command.ClientInfo{Orchestrator: "swarm"} }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… and here
cli/command/stack/deploy.go
Outdated
if dockerCli.ClientInfo().HasKubernetes() { | ||
switch { | ||
case dockerCli.ClientInfo().HasAll(): | ||
return fmt.Errorf("Please specify an orchestrator (swarm|kubernetes)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want to share this error somehow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK!
cmd/docker/docker.go
Outdated
@@ -54,7 +54,7 @@ func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command { | |||
flags = cmd.Flags() | |||
flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit") | |||
flags.StringVar(&opts.ConfigDir, "config", cliconfig.Dir(), "Location of client config files") | |||
opts.Common.InstallFlags(flags) | |||
opts.Common.InstallFlags(flags, cmd.PersistentFlags()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get this change, this feels really weird to add the flag twice (on cmd.Flags()
and cmd.PersistentFlags()
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"orchestrator" is the only flag added to cmd.PersistentFlags() in InstallFlags, all the other flags are still in cmd.Flags()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That being said if you would rather have me remove that last commit, I'd be fine with that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly confused as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll just remove the related commit.
@vdemeester I fixed all comments except the ones under discussion about the flags e.g.
Would you kindly please take another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds a lot of complexity to the codebase, and I'm not sure if all is needed. I left some comments inline, but must admit some of the flow is a bit hard to follow
cli/flags/common.go
Outdated
@@ -55,7 +55,7 @@ func (commonOpts *CommonOptions) InstallFlags(flags *pflag.FlagSet) { | |||
flags.StringVarP(&commonOpts.LogLevel, "log-level", "l", "info", `Set the logging level ("debug"|"info"|"warn"|"error"|"fatal")`) | |||
flags.BoolVar(&commonOpts.TLS, "tls", dockerTLS, "Use TLS; implied by --tlsverify") | |||
flags.BoolVar(&commonOpts.TLSVerify, FlagTLSVerify, dockerTLSVerify, "Use TLS and verify the remote") | |||
flags.StringVar(&commonOpts.Orchestrator, "orchestrator", "", "Which orchestrator to use with the docker cli (swarm|kubernetes) (default swarm) (experimental)") | |||
flags.StringVar(&commonOpts.Orchestrator, "orchestrator", "", "Which orchestrator to use with the docker cli (swarm|kubernetes|all) (default swarm) (experimental)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like (default swarm)
no longer matches reality (for example, having "orchestrator":"kubernetes"
in my ~/.docker/config.json
would set the default)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. I'll remove the (default swarm)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this was there before but I don't thing with the docker cli
brings anything and the other flag descriptions don't have it. I'll remove it too.
cli/command/stack/list.go
Outdated
}, | ||
} | ||
|
||
flags := cmd.Flags() | ||
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template") | ||
flags.BoolVarP(&opts.AllNamespaces, "all-namespaces", "", false, "List stacks among all Kubernetes namespaces") | ||
flags.SetAnnotation("all-namespaces", "kubernetes", nil) | ||
flags.SetAnnotation("all-namespaces", "experimentalCLI", nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this change to all-namespaces
should be done in the other PR (#991)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, too late though as #991 has been merged in the meanwhile…
cli/command/stack/list.go
Outdated
@@ -28,6 +28,9 @@ func newListCommand(dockerCli command.Cli) *cobra.Command { | |||
|
|||
flags := cmd.Flags() | |||
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template") | |||
flags.StringSliceVar(&opts.Namespaces, "namespace", []string{}, "Kubernetes namespaces to use") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we use two separate approaches for the namespace
flag? Looks like we define it twice now: once through AddNamespaceFlag()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All docker stack
sub-commands use AddNamespaceFlag
and have a namespace
flag defined as a StringVar
except ls
which has a namespace
flag defined as a StringSliceVar
.
This is because for all sub-commands but ls
only one --namespace
can be set whereas ls
can have several, e.g. docker stack ls --namespace=tutu,default,bla
or docker stack ls --namespace=tutu --namespace=default --namespace=bla
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering now if this should be a StringSliceVar
or a StringVar
; I think StringVar
can be specified multiple times (--namespace=bla --namespace=foo
), but does not support comma-separated values; we haven't documented using comma-separated values, and don't think we support it for other options (possibly --security-opt
only)
(note that if a command only accepts a single namespace, we could still produce an error if multiple are given)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take another look but from what I remember there was no way to make it look nice, for both cases, e.g.
$ docker stack ps --help
…
Options:
…
--namespace string Kubernetes namespace to use
VS
$ ./build/docker.exe stack ls --help
…
Options:
…
--namespace strings Kubernetes namespaces to use
Also I don't see how a single StringVar
can hold multiple --namespace
values…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think StringVar can be specified multiple times (--namespace=bla --namespace=foo), but does not support comma-separated values
In that case the latest value is silently selected (here foo
), I suppose the flags are simply processed in order.
If we just let comma-separated values out of the question we could indeed emulate both behaviors with a StringSliceVar
by using the last element when only one namespace is required.
(Incidentally passing --namespace=bla,foo
to a StringVar
flag yields a value of bla,foo
…)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The best I could come up with by using []string
on the stack
command level is
$ ./build/docker.exe stack --help
Usage: docker stack COMMAND
Manage Docker stacks
Options:
--kubeconfig string Kubernetes config file
--namespace strings Kubernetes namespace to use
This is wrong for all sub-commands as for most of them it says strings
plural whereas only one is supported (and differs for instance from kubeconfig
), and for docker stack ls
which supports several namespaces the description should have namespaces
…
I don't see how to have types and descriptions accurate for all sub-commands without duplicating the flag.
cli/command/stack/list.go
Outdated
} | ||
mnms := map[string]struct{}{} | ||
for _, nm := range nms { | ||
mnms[nm] = struct{}{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is to get rid of duplicates? This feels a bit like premature optimisation, also I'd expected this to return a []string
(matching the type before removing duplicates)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this is to remove duplicates, again to match kubectl
behavior. I'll change the return type to a []string
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…and refactor it to
func removeDuplicates(namespaces []string) []string {
mnms := map[string]struct{}{}
for _, nm := range namespaces {
mnms[nm] = struct{}{}
}
namespaces = []string{}
for nm := range mnms {
namespaces = append(namespaces, nm)
}
return namespaces
}
cli/command/stack/kubernetes/cli.go
Outdated
if len(namespace) > 0 { | ||
opts.Namespace = namespace[0] | ||
} else if nm, err := flags.GetString("namespace"); err == nil { | ||
opts.Namespace = nm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's now opts.Namespaces
(for stacks) and opts.Namespace
, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there first one is of type []string
and the latter string
.
cli/command/stack/list.go
Outdated
ss, err := kubernetes.GetStacks(kli, opts) | ||
if err != nil { | ||
return err | ||
if opts.AllNamespaces || len(mnms) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't len(opts.Namespaces)
give the same here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, nice catch!
cli/command/stack/list.go
Outdated
return ss, nil | ||
} | ||
|
||
func getNamespaces(cmd *cobra.Command) (map[string]struct{}, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could just take (flags *flag.FlagSet
, or even namespaces []string
, then call it with getNamespaces(cmd.Flags())
, but see my other comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has actually been changed to receive a flags *flag.FlagSet
in a follow-up PR, but I might as well do it there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm sorry I meant []string
and passing it opts.Namespaces
…
cli/command/stack/kubernetes/cli.go
Outdated
@@ -23,20 +23,28 @@ type Options struct { | |||
} | |||
|
|||
// NewOptions returns an Options initialized with command line flags | |||
func NewOptions(flags *flag.FlagSet) Options { | |||
func NewOptions(flags *flag.FlagSet, namespace ...string) Options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both flags
and namespace
basically come from cmd.Flags()
; why pass both, if we have all information in flags
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way Kubernetes works implies that listing the stacks (or anything else) must be made within the context of a namespace, thus as we want to merge the lists of stacks from different namespaces we create a new kubernetes.Options
for each namespace when iterating over them for docker stack ls
.
I'll refactor the code to separate the different behaviors in respect to namespaces.
cli/command/stack/kubernetes/cli.go
Outdated
opts.Namespace = namespace | ||
if len(namespace) > 0 { | ||
opts.Namespace = namespace[0] | ||
} else if nm, err := flags.GetString("namespace"); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in what situation would flags.GetString("namespace")
give anything different than namespace[0]
? If we only expect a single namespace to be passed, it should not take more than one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is again due to the discrepancy between docker stack ls
and the other docker stack
sub-commands regarding the number of --namespace
flags allowed.
cmd/docker/docker.go
Outdated
@@ -54,7 +54,7 @@ func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command { | |||
flags = cmd.Flags() | |||
flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit") | |||
flags.StringVar(&opts.ConfigDir, "config", cliconfig.Dir(), "Location of client config files") | |||
opts.Common.InstallFlags(flags) | |||
opts.Common.InstallFlags(flags, cmd.PersistentFlags()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly confused as well
This needs a rebase now |
@thaJeztah I believe the code to be much clearer now, thank you for your comments! |
cli/command/stack/list.go
Outdated
kopts := kubernetes.NewOptions(cmd.Flags()) | ||
if opts.AllNamespaces || len(opts.Namespaces) == 0 { | ||
if dockerCli.ClientInfo().HasAll() { | ||
opts.AllNamespaces = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if you have orchestrator=all
and then you do docker stack ls --namespace=foobar
, this will still return all stacks in every namespace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch is only executed if opts.AllNamespaces || len(opts.Namespaces) == 0
e.g. there is already --orchestrator=all
or no --namespace
.
Here is what this gives me:
$ ./build/docker.exe --orchestrator=all stack ls
NAME SERVICES ORCHESTRATOR NAMESPACE
blaaaaaa 1 Kubernetes default
blaaaaaaaaa 1 Kubernetes default
dtc 5 Kubernetes tutu
dtc 5 Kubernetes tata
dtcccccc 5 Kubernetes default
$ ./build/docker.exe --orchestrator=all stack ls --namespace=tata
NAME SERVICES ORCHESTRATOR NAMESPACE
dtc 5 Kubernetes tata
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks reasonable to me, but I'll let @vdemeester and @thaJeztah have the final say.
cli/command/stack/list.go
Outdated
kopts := kubernetes.NewOptions(cmd.Flags()) | ||
if opts.AllNamespaces || len(opts.Namespaces) == 0 { | ||
if dockerCli.ClientInfo().HasAll() { | ||
opts.AllNamespaces = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see now.
cli/command/stack/list.go
Outdated
if dockerCli.ClientInfo().HasKubernetes() { | ||
kopts := kubernetes.NewOptions(cmd.Flags()) | ||
if opts.AllNamespaces || len(opts.Namespaces) == 0 { | ||
if dockerCli.ClientInfo().HasAll() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is redundant, because we already checked HasKubernetes()
, which also checks for HasAll()
;
// HasKubernetes checks if kubernetes orchestrator is enabled
func (c ClientInfo) HasKubernetes() bool {
return c.HasExperimental && (c.Orchestrator == OrchestratorKubernetes || c.Orchestrator == OrchestratorAll)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--orchestrator=kubernetes
yields HasKubernetes()
true
and HasAll()
false
--orchestrator=all
yields both HasKubernetes()
true
and HasAll()
true
So if HasAll()
implies HasKubernetes()
, the reverse is not necessary true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But here HasAll()
(ie --orchestrator=all
) is used to enable --all-namespaces
; I don't see how those relate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a UX requirement defined in the PRD
- Provide intuitive mechanisms for switching Kubernetes namespace:
- When targeting all orchestrators, target all namespaces by default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having trouble conflating these; this may become very confusing:
- configuration has
"orchestrator: all"
:docker stack ls
shows all stacks (both swarm and k8s) - I want to view only the
k8s
stacks, so I add--orchestrator=kubernetes
. Now I no longer see all my stacks, only those in thedefault
namespace - confused
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thinking behind this was as follows: When you list stacks across orchestrators your intention is to see all the stacks running on your cluster. When you specify kubernetes
as your orchestrator; you are doing something more specific and want similar behaviour to what kubectl
gives you.
I can see how this might be confusing for your flow. There will be a NAMESPACE column which should help the user understand what has happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, see you're referring to the case when a user has set orchestrator
to all
in their config file. I don't think many users will do this as they will only be able to list resources. In order to manipulate resources, they will need to specify an orchestrator.
cli/command/stack/list.go
Outdated
} | ||
namespaces = []string{} | ||
for nm := range mnms { | ||
namespaces = append(namespaces, nm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to loop twice here, could be something like;
func removeDuplicates(namespaces []string) []string {
found := make(map[string]bool)
results := namespaces[:0]
for _, n := range namespaces {
if !found[n] {
results = append(results, n)
found[n] = true
}
}
return results
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, I'll change that.
cli/command/stack/list.go
Outdated
@@ -28,6 +28,9 @@ func newListCommand(dockerCli command.Cli) *cobra.Command { | |||
|
|||
flags := cmd.Flags() | |||
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template") | |||
flags.StringSliceVar(&opts.Namespaces, "namespace", []string{}, "Kubernetes namespaces to use") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering now if this should be a StringSliceVar
or a StringVar
; I think StringVar
can be specified multiple times (--namespace=bla --namespace=foo
), but does not support comma-separated values; we haven't documented using comma-separated values, and don't think we support it for other options (possibly --security-opt
only)
(note that if a command only accepts a single namespace, we could still produce an error if multiple are given)
Could there be something missing in this PR? Trying inside the build container (no kubernetes enabled, but experimental features on)'
Now, trying this;
|
This looks like what we want because
The orchestrator flag must be right after
Passing Or am I missing something? |
hm, right; I'm in doubt if we should only accept it as a global flag. I know users can get very confused as to "where" to pass a flag; existing examples are, e.g. |
@thaJeztah I brought the refactoring over from https://github.com/docker/cli/pull/1034/files/e0dbcb3b88f615d358fc5bed93ca3d14aa094d87..691eeff5a5db87be3fe5e0f1ca852024edf08f1c#diff-0ade8f01def39989ced9bb51bab08a69 |
Signed-off-by: Mathieu Champlon <mathieu.champlon@docker.com>
@vdemeester @thaJeztah I can remove the last commit if that helps moving forward with this PR (and either open a separate PR with it or just forget about it)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code generally LGTM, but perhaps we should indeed move the refactor out of this PR (t.b.h., I don't recall suggesting that change, but it could've been me, idk)
cli/command/stack/cmd.go
Outdated
"github.com/docker/cli/cli" | ||
"github.com/docker/cli/cli/command" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var errUnsupportedAllOrchestrator = fmt.Errorf("Please specify an orchestrator (swarm|kubernetes)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking of rephrasing this (also in light of #770); perhaps;
No orchestrator specified. Use either "kubernetes" or "swarm"
(better suggestions welcome)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an error message shouldn't it start with a lower case? I would probably avoid the dot too, e.g.
no orchestrator specified, use either "kubernetes" or "swarm"
or
no orchestrator specified: use either "kubernetes" or "swarm"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this one:
no orchestrator specified: use either "kubernetes" or "swarm"
composeClient, err := kubeCli.composeClient() | ||
if err != nil { | ||
return nil, err | ||
} | ||
stackSvc, err := composeClient.Stacks(allNamespaces) | ||
stackSvc, err := composeClient.Stacks(opts.AllNamespaces) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR, but we should consider passing an opts
here, instead of a boolean (opts.AllNamespaces
) to prevent future bloat in the signature
I still have reservations on the magic relation between I'm having trouble conflating these; this may become very confusing:
The thinking behind this was as follows: When you list stacks across orchestrators your intention is to see all the stacks running on your cluster. When you specify I can see how this might be confusing for your flow. There will be a NAMESPACE column which should help the user understand what has happened. @chris-crone : Ah, see you're referring to the case when a user has set
I'm actually not sure: I can definitely see it being useful to just run any Which brings me to two things to consider:
|
I removed the commit with the tests refactoring and changed the error message when an orchestrator must be explicitly specified. |
All other docker stack commands report an error when passed this value. Signed-off-by: Mathieu Champlon <mathieu.champlon@docker.com>
@mat007 could you move the It's three lines, so easy to review from a code-perspective, so if we get agreement on that one, we should be able to merge that one fast; if dockerCli.ClientInfo().HasAll() {
opts.AllNamespaces = true
} |
Signed-off-by: Mathieu Champlon <mathieu.champlon@docker.com>
@thaJeztah done! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
sorry for all the hence-and-forth 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🐯
Just to keep track, the all orchestrator all namespace work is in #1059. |
- What I did
Made it easier to work with both swarm and kubernetes stacks combined, e.g.
stack ls
for the valueall
in the--orchestrator
flag which triggers the display of both swarm and kubernetes stacks--namespace
for docker stack ls- How I did it
- How to verify it
- Description for the changelog
- A picture of a cute animal (not mandatory but encouraged)